/*
===========================================================================
This source file is part of DyLab (Dynamic Laboratory)
For the latest info, see http://dylab.googlecode.com

Copyright (c) 2006-2008 Lukas Krejci
(krejci.lukas@volny.cz)

This file is part of DyLab.

    DyLab is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DyLab is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DyLab.  If not, see <http://www.gnu.org/licenses/>.
===========================================================================
*/

#ifndef __dylab_MassPoint_h__
#define __dylab_MassPoint_h__

//===========================================================================================
#include <dylab/utils/containers/HashObjContainer.h>
#include <dylab/utils/BitFlags.h>
#include <dylab/utils/geometry/Vector3.h>

//===========================================================================================
namespace dylab {

    /// This class represents one mass point.
    class DYLAB_EXPORT MassPoint
    {
    private:
        typedef BitFlags8 BitFlagsT;
    public:
        /// Mass point flag codes.
        enum flags_t
        {
            F_BOUNDARY = 0,
            F_FIXED
        };
        /// The type of mass point identification.
        typedef uint32_t id_t;
		//-----------------------------------------------------------------------------
		/// Mass point's state attributes.
		struct State
		{
			State()
					{ }
			State(const Vector3 & _pos, const Vector3 & _vel, const Vector3 & _force)
				: position(_pos), velocity(_vel), force(_force)
					{ }
			/// Current position
			Vector3 position;
	        /// Current mass point velocity vector
		    Vector3 velocity;   
            /// Current mass point force vector
            Vector3 force;
		};
		//-----------------------------------------------------------------------------
		/// Maximum number of mass point history records.
		enum
		{ MAX_HISTORY_SIZE = 4 };
		//-----------------------------------------------------------------------------
		/// Mass point's history
		class DYLAB_EXPORT HistoryStates
		{ 
		private:
			/// Number of histry states
			uint32_t mSize;
			/// History states
			State * mStates[MAX_HISTORY_SIZE];
		public:
			/// The constructor creates required number of state structures					
			/// and populates them with values of the current state.
			HistoryStates(uint32_t _size, const State & _currState);
			/// Destructor deletes all previously created states
			~HistoryStates();
			/// Stores the current state into the history shifting it one step back.
			void storeState(const State & _currState);
			/// Retrieves the state with the given index.
			inline State * getState(uint32_t _index)
					{ DYLAB_ASSERT(_index < mSize); return mStates[_index]; }
			/// Retrieves the state with the given index, const version.
			inline const State * getState(uint32_t _index) const
					{ DYLAB_ASSERT(_index < mSize); return mStates[_index]; }
			/// Returns the number available history of states.
			inline uint32_t getSize() const
					{ return mSize; }
		};
		//-----------------------------------------------------------------------------				
    protected:
        /// Mass point identification number
        id_t mId;
        /// Mass of the point
        real_t mMass;  
        /// Current mass point's flags
        BitFlagsT mFlags;
		/// Mass point's current state
		State mCurrState;
		/// Mass point's histroy
		HistoryStates * mHistoryStates;
    private:
        /// Default construction is not allowed.
        MassPoint();
    public:
        MassPoint(id_t _id, const Vector3 & _pos = Vector3::ZERO, 
			real_t _mass = Math::ZERO, BitFlagsT::data_t _flags = 0);
        virtual ~MassPoint();

        inline id_t getId() const
                { return mId; }

        inline void setMass(real_t _mass)
                { mMass = _mass; }
        inline real_t getMass() const
                { return mMass; }
        
        inline BitFlagsT & flags()
                { return mFlags; }
        inline const BitFlagsT & flags() const
                { return mFlags; }

        /// Returns mass point's current state.
        inline State & currState()
                { return mCurrState; }
        /// Returns mass point's current state, const version.
        inline const State & currState() const
                { return mCurrState; }

		/// Reserve the specified minimal number of history states.
		void reserveHistoryStates(uint32_t _noStates);

		/// Stores the current state into the history, shifting all other history states one step back.
		inline void storeState()
				{ DYLAB_ASSERT(mHistoryStates != NULL); mHistoryStates->storeState(mCurrState); }

		/** Returns mass point's previous state with the given nubmer of steps back in history.
		@remarks History steps counting starts from 1.
		*/
		inline State & historyState(uint32_t _stepsBack)
				{ DYLAB_ASSERT(mHistoryStates != NULL); return *(mHistoryStates->getState(_stepsBack - 1)); }

		/** Returns mass point's previous state with the given nubmer of steps back in history, const version.
		@remarks History steps counting starts from 1.
		*/
		inline const State & historyState(uint32_t _stepsBack) const
				{ DYLAB_ASSERT(mHistoryStates != NULL); return *(mHistoryStates->getState(_stepsBack - 1)); }
	};
    //-----------------------------------------------------------------------------

    //===========================================================================================    
	inline std::ostream & operator << (std::ostream & _os, const MassPoint::State & _o)
            { return _os << String::fmt("pos(%1%) vel(%2%) force(%3%)", _o.position, _o.velocity, _o.force); }

	//===========================================================================================    	
	/// Defines the hash container mapping mass point id to the instance of class MassPoint.
    class DYLAB_EXPORT MassPointContainer
        : public HashObjContainer<MassPoint::id_t, MassPoint>
    {
    public:
        MassPointContainer(bool _objectOwner)
            : HashObjContainer<MassPoint::id_t, MassPoint>(_objectOwner)
                { }
    };
    //-----------------------------------------------------------------------------
}
//===========================================================================================
#endif // __dylab_MassPoint_h__
